home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Freeware 1998 June
/
SGI Freeware 1998 June.iso
/
dist
/
fw_ATxgopher.idb
/
usr
/
freeware
/
src
/
xgopher.1.3
/
gui.c.z
/
gui.c
Wrap
C/C++ Source or Header
|
1998-01-21
|
31KB
|
1,332 lines
/* gui.c
Implement functions of the GUI (Graphical User Interface).
The GUI is the X window system. This file is the interface
to all other X-related functions in panel.c, error.c, save.c,
text.c, etc. */
/*---------------------------------------------------------------*/
/* Xgopher version 1.3 08 April 1993 */
/* version 1.2 20 November 1992 */
/* version 1.1 20 April 1992 */
/* version 1.0 04 March 1992 */
/* X window system client for the University of Minnesota */
/* Internet Gopher System. */
/* Allan Tuchman, University of Illinois at Urbana-Champaign */
/* Computing and Communications Services Office */
/* Copyright 1992, 1993 by */
/* the Board of Trustees of the University of Illinois */
/* Permission is granted to freely copy and redistribute this */
/* software with the copyright notice intact. */
/*---------------------------------------------------------------*/
#include <stdio.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xaw/Simple.h> /* where XtNcursor is */
#include <X11/Xmu/Converters.h>
#include <X11/cursorfont.h>
#include <X11/Xaw/Text.h>
#include "conf.h"
#include "gui.h"
#include "panel.h"
#include "error.h"
#include "globals.h"
#include "xglobals.h"
#include "appres.h"
#include "popres.h"
#include "typeres.h"
#include "util.h"
#include "status.h"
#include "compatR4.h"
#include "itemList.h"
#include "dirList.h"
#include "markList.h"
#include "itemInfo.h"
#include "help.h"
#include "cso.h"
#include "index.h"
#include "text.h"
#include "options.h"
#include "single.h"
#include "gopher.h"
#include "osdep.h"
gopherAppResources * getApplicationResources(
);
static Widget topLevel;
static Boolean windowStarted = False;
static Boolean errorDialogExists = FALSE;
static Boolean infoDialogExists = FALSE;
static Boolean saveDialogExists = FALSE;
static Boolean csoPanelExists = FALSE;
static Boolean indexPanelExists = FALSE;
static Boolean optionsPanelExists = FALSE;
static Boolean singlePanelExists = FALSE;
static XtWorkProcId nullWPID = (XtWorkProcId) 0;
static XtWorkProcId saveWPID = (XtWorkProcId) 0,
indexWPID = (XtWorkProcId) 0,
csoWPID = (XtWorkProcId) 0,
errWPID = (XtWorkProcId) 0,
infoWPID = (XtWorkProcId) 0,
optionsWPID = (XtWorkProcId) 0,
singleWPID = (XtWorkProcId) 0;
static char *emptyList[] = {"<none>", NULL};
static String fallbackResources[] = {
"",
(char *) NULL
};
/* initGUI
Initialize the X window system */
BOOLEAN
initGUI(argc, argv)
int *argc;
char **argv;
{
static XtPointer scr;
static XtConvertArgRec screenConvertArg[] = {
{XtAddress, (XtPointer)&scr, sizeof(Screen *)}
};
Arg args[5];
XrmOptionDescRec opts[2];
Cardinal narg = (Cardinal) 0,
nopt = (Cardinal) 0;
#ifndef XGOPHER_X11R4
int *cArgc = argc;
#else
Cardinal *cArgc = (Cardinal *) argc;
#endif
/* initialize X window system */
topLevel = XtAppInitialize (&appcon, GOPHER_CLASS,
opts, nopt, cArgc, argv,
fallbackResources, args, narg);
scr = (XtPointer) XtScreen(topLevel);
XtAppAddConverter(appcon, XtRString, XtRPixmap, XmuCvtStringToBitmap,
screenConvertArg, XtNumber(screenConvertArg));
XtAppSetTypeConverter(appcon, XtRString, XgRShowLevel,
(XtTypeConverter) cvtStringToShowLevel,
NULL, (Cardinal) 0,
XtCacheNone, NULL);
XtAppSetTypeConverter(appcon, XtRString, XgRPositionFrom,
(XtTypeConverter) cvtStringToPositionFrom,
NULL, (Cardinal) 0,
XtCacheNone, NULL);
XtAppSetTypeConverter(appcon, XtRString, XgRJustification,
(XtTypeConverter) cvtStringToJustification,
NULL, (Cardinal) 0,
XtCacheNone, NULL);
XtAppSetTypeConverter(appcon, XtRString, XgRCopyType,
(XtTypeConverter) cvtStringToCopyType,
NULL, (Cardinal) 0,
XtCacheNone, NULL);
if (! getOptions(*argc, argv)) return FALSE;
windowStarted = True;
return TRUE;
}
/* "done" macro from the Xmu library - used by those type converters */
#define done(type, value) \
{ \
if (toVal->addr != NULL) { \
if (toVal->size < sizeof(type)) { \
toVal->size = sizeof(type); \
return False; \
} \
*(type*)(toVal->addr) = (value); \
} \
else { \
static type static_val; \
static_val = (value); \
toVal->addr = (XtPointer)&static_val; \
} \
toVal->size = sizeof(type); \
return True; \
}
/* cvtStringToShow
type converter for show resource keywords to enumerated type values */
Boolean
cvtStringToShowLevel(dpy, args, numArgs, fromVal, toVal, closureRet)
Display *dpy;
XrmValuePtr args;
Cardinal *numArgs;
XrmValuePtr fromVal, toVal;
XtPointer *closureRet;
{
char *s = (char *) fromVal->addr;
if (s == NULL) return;
if (strcasecmp(showEAll, s) == 0)
done( int, (int) showAll );
if (strcasecmp(showEKnown, s) == 0)
done( int, (int) showKnown );
if (strcasecmp(showEAccessible, s) == 0)
done( int, (int) showAccessible );
if (strcasecmp(showEAvailable, s) == 0)
done( int, (int) showAvailable );
XtDisplayStringConversionWarning(dpy, s, XgRShowLevel);
return False;
}
/* cvtStringToPositionFrom
type converter for positionFrom resource to enumerated type values */
Boolean
cvtStringToPositionFrom(dpy, args, numArgs, fromVal, toVal, closureRet)
Display *dpy;
XrmValuePtr args;
Cardinal *numArgs;
XrmValuePtr fromVal, toVal;
XtPointer *closureRet;
{
char *s = (char *) fromVal->addr;
if (s == NULL) return;
if (strcasecmp(fromENone, s) == 0)
done( int, (int) from_none );
if (strcasecmp(fromEPointer, s) == 0)
done( int, (int) from_pointer );
if (strcasecmp(fromEMain, s) == 0)
done( int, (int) from_main );
if (strcasecmp(fromEScreen, s) == 0)
done( int, (int) from_screen );
if (strcasecmp(fromEWidget, s) == 0)
done( int, (int) from_widget );
XtDisplayStringConversionWarning(dpy, s, XgRPositionFrom);
return False;
}
/* cvtStringToJustification
type converter for Justification resource to enumerated type values */
Boolean
cvtStringToJustification(dpy, args, numArgs, fromVal, toVal, closureRet)
Display *dpy;
XrmValuePtr args;
Cardinal *numArgs;
XrmValuePtr fromVal, toVal;
XtPointer *closureRet;
{
char *s = (char *) fromVal->addr;
if (s == NULL) return;
if (strcasecmp(justETop, s) == 0 || strcasecmp(justELeft, s) == 0 )
done( int, (int) justify_top_left );
if (strcasecmp(justECenter, s) == 0)
done( int, (int) justify_center );
if (strcasecmp(justEBottom, s) == 0 || strcasecmp(justERight, s) == 0)
done( int, (int) justify_bottom_right );
XtDisplayStringConversionWarning(dpy, s, XgRJustification);
return False;
}
/* cvtStringToCopyType
type converter for datatype resource keywords to enumerated type values */
Boolean
cvtStringToCopyType(dpy, args, numArgs, fromVal, toVal, closureRet)
Display *dpy;
XrmValuePtr args;
Cardinal *numArgs;
XrmValuePtr fromVal, toVal;
XtPointer *closureRet;
{
char *s = (char *) fromVal->addr;
if (s == NULL) return;
if (strcasecmp(copyTypeENone, s) == 0)
done( int, (int) copyTypeNone );
if (strcasecmp(copyTypeEAscii, s) == 0)
done( int, (int) copyTypeAscii );
if (strcasecmp(copyTypeEBinary, s) == 0 ||
strcasecmp(copyTypeEBinaryEOF, s) == 0)
done( int, (int) copyTypeBinaryEOF );
if (strcasecmp(copyTypeEUnspec, s) == 0)
done( int, (int) copyTypeUnspec );
XtDisplayStringConversionWarning(dpy, s, XgRCopyType);
return False;
}
/* initMainPanel
creates the main Xgopher panel */
BOOLEAN
initMainPanel()
{
makeGopherPanel(topLevel);
XtRealizeWidget(topLevel);
makeStatusPanel(topLevel);
}
/* getOptions
Use the GUI (X window system) to access application options */
static BOOLEAN
getOptions(argc, argv)
int argc;
char **argv;
{
if ((appResources = getApplicationResources(topLevel, argc, argv)) ==
NULL)
return False;
else
return True;
}
/* closeGUIandQuit
terminate the GUI (X window system) cleanly, then exit the application */
void
closeGUIandQuit(rc)
int rc;
{
XtDestroyApplicationContext(appcon);
exit(rc);
}
/* loadMarks
load bookmarks from the bookmark file */
void
loadMarks()
{
markLoadProc(NULL, NULL, NULL);
}
/* makeSaveDialogWorkProc
X work proc to create the Save Dialog during spare cycles. */
static Boolean
makeSaveDialogWorkProc(clientData)
XtPointer clientData;
{
Widget topLevel = (Widget) clientData;
makeSaveDialog(topLevel);
saveDialogExists = TRUE;
return TRUE;
}
/* makeInfoDialogWorkProc
X work proc to create the Info Dialog during spare cycles. */
static Boolean
makeInfoDialogWorkProc(clientData)
XtPointer clientData;
{
Widget topLevel = (Widget) clientData;
makeInfoDialog(topLevel);
infoDialogExists = TRUE;
return TRUE;
}
/* makeErrorDialogWorkProc
X work proc to create the Error Dialog during spare cycles. */
static Boolean
makeErrorDialogWorkProc(clientData)
XtPointer clientData;
{
Widget topLevel = (Widget) clientData;
makeErrorDialog(topLevel);
errorDialogExists = TRUE;
return TRUE;
}
/* makeCsoPanelWorkProc
X work proc to create the CSO (ph) panel during spare cycles. */
static Boolean
makeCsoPanelWorkProc(clientData)
XtPointer clientData;
{
Widget topLevel = (Widget) clientData;
makeCsoPanel(topLevel);
csoPanelExists = TRUE;
return TRUE;
}
/* makeIndexWorkProc
X work proc to create the Index Search panel during spare cycles. */
static Boolean
makeIndexWorkProc(clientData)
XtPointer clientData;
{
Widget topLevel = (Widget) clientData;
makeIndexPanel(topLevel);
indexPanelExists = TRUE;
return TRUE;
}
/* makeOptionsWorkProc
X work proc to create the Options panel during spare cycles. */
static Boolean
makeOptionsWorkProc(clientData)
XtPointer clientData;
{
Widget topLevel = (Widget) clientData;
makeOptionsPanel(topLevel);
optionsPanelExists = TRUE;
return TRUE;
}
/* makeSingleWorkProc
X work proc to create the Single Item panel during spare cycles. */
static Boolean
makeSingleWorkProc(clientData)
XtPointer clientData;
{
Widget topLevel = (Widget) clientData;
makeSinglePanel(topLevel);
singlePanelExists = TRUE;
return TRUE;
}
/* markCurrentDirectory
set a bookmark at the current directory (by an event other than
the standard click on the bookmark button) */
void
markCurrentDirectory()
{
markProc(NULL, NULL, NULL);
}
/* doUserRequests
The main loop in the GUI process - await user events, and process them. */
void
doUserRequests()
{
saveWPID = XtAppAddWorkProc (appcon, makeSaveDialogWorkProc,
(XtPointer) topLevel);
indexWPID = XtAppAddWorkProc (appcon, makeIndexWorkProc,
(XtPointer) topLevel);
csoWPID = XtAppAddWorkProc (appcon, makeCsoPanelWorkProc,
(XtPointer) topLevel);
infoWPID = XtAppAddWorkProc (appcon, makeInfoDialogWorkProc,
(XtPointer) topLevel);
singleWPID = XtAppAddWorkProc (appcon, makeSingleWorkProc,
(XtPointer) topLevel);
optionsWPID = XtAppAddWorkProc (appcon, makeOptionsWorkProc,
(XtPointer) topLevel);
errWPID = XtAppAddWorkProc (appcon, makeErrorDialogWorkProc,
(XtPointer) topLevel);
XtAppMainLoop(appcon);
}
/* makeXThings
make things such as icons, bitmaps, and parsed translation tables
that the application will need */
#include "oneLine.h"
#include "bitmaps/pgdown.xbm"
#include "bitmaps/pgup.xbm"
#include "bitmaps/pulldown.xbm"
#include "bitmaps/check.xbm"
#include "bitmaps/uncheck.xbm"
#include <X11/bitmaps/gray3>
void
makeXThings()
{
wmDeleteAtom = XInternAtom(XtDisplay(topLevel), "WM_DELETE_WINDOW",
False);
oneLineParsed = XtParseTranslationTable(OneLineTextTr);
pageDownPixmap = XCreateBitmapFromData (XtDisplay(topLevel),
RootWindowOfScreen(XtScreen(topLevel)),
(char *) pgdown_bits,
pgdown_width, pgdown_height);
pageUpPixmap = XCreateBitmapFromData (XtDisplay(topLevel),
RootWindowOfScreen(XtScreen(topLevel)),
(char *) pgup_bits,
pgup_width, pgup_height);
pulldownPixmap = XCreateBitmapFromData (XtDisplay(topLevel),
RootWindowOfScreen(XtScreen(topLevel)),
(char *) pulldown_bits,
pulldown_width,
pulldown_height);
gray = XCreatePixmapFromBitmapData (XtDisplay(topLevel),
RootWindowOfScreen(XtScreen(topLevel)),
(char *) gray3_bits,
gray3_width, gray3_height,
BlackPixelOfScreen(XtScreen(topLevel)),
WhitePixelOfScreen(XtScreen(topLevel)),
DefaultDepthOfScreen(XtScreen(topLevel))
);
checkPixmap = XCreateBitmapFromData (XtDisplay(topLevel),
RootWindowOfScreen(XtScreen(topLevel)),
(char *) check_bits,
check_width, check_height);
uncheckPixmap = XCreateBitmapFromData (XtDisplay(topLevel),
RootWindowOfScreen(XtScreen(topLevel)),
(char *) uncheck_bits,
uncheck_width, uncheck_height);
}
/* getSelectedItem
get the currently selected gopher item */
gopherItemP
getSelectedItem()
{
return whichItemSelected();
}
/* showError
Cause an error message to be displayed on the user's screen. */
void
showError(message)
char *message;
{
if (windowStarted) {
if (! errorDialogExists) {
makeErrorDialog(topLevel);
errorDialogExists = TRUE;
if (errWPID != nullWPID) XtRemoveWorkProc (errWPID);
}
displayError(message, False);
} else {
fprintf (stderr, "NOTE!\n%s\n", message);
}
LOG (logFP, "ERROR:\n%s\n", message);
}
/* showFatalError
Cause a fatal error message to be displayed on the user's screen. */
void
showFatalError(message)
char *message;
{
if (windowStarted) {
if (! errorDialogExists) {
makeErrorDialog(topLevel);
errorDialogExists = TRUE;
if (errWPID != nullWPID) XtRemoveWorkProc (errWPID);
}
displayError(message, True);
} else {
fprintf (stderr, "NOTE: Unrecoverable error!\n%s\n", message);
}
LOG (logFP, "FATAL ERROR:\n%s\n", message);
}
/* showInfo
Cause an information message to be displayed on the user's screen. */
void
showInfo(message)
char *message;
{
if (windowStarted) {
if (! infoDialogExists) {
makeInfoDialog(topLevel);
infoDialogExists = TRUE;
if (infoWPID != nullWPID) XtRemoveWorkProc (infoWPID);
}
displayInfo(message);
} else {
fprintf (stderr, "NOTE!\n%s\n", message);
}
}
/* showStatus
indicate status of the gopher process to the user by messages, icons,
and/or cursor changes. */
void
showStatus(message, statType, host, port)
char *message;
statusType statType;
char *host;
int port;
{
if (! windowStarted) return;
if (statType != STAT_USER) {
displayStatusPanel(statType, message, host, port);
} else {
removeStatusPanel();
}
}
/* displayCurrent
display the current directory. */
void
displayCurrent()
{
gopherItemP gi;
int i, need;
static int dirStringListLen = 0;
static char **dirStringList = NULL;
gopherDirP current = getCurrentDir();
if (current != NULL) {
LOG(logFP,
"Current directory: \'%s'\n\tSelector \'%s\'\n\tat \'%s\' %d\n",
USER_STRING(current->selectorItem),
vStringValue(&(current->selectorItem->selector)),
current->selectorItem->host,
current->selectorItem->port);
}
if (!windowStarted) return;
if (current != NULL) {
if (current->created == NOT_LOADED)
updateDirectory(current);
}
/* The array of string pointers is allocated a reasonably
large amount initially. After this, if more are needed,
the current array is freed, then the new required number
is allocated. */
if (current != NULL) {
need = itemListLength(&(current->contents)) + 1;
} else {
need = 0;
}
if (need > dirStringListLen) {
need = need > MIN_DIR_STRING_LIST_LEN ?
need : MIN_DIR_STRING_LIST_LEN;
if (dirStringList != NULL) free(dirStringList);
dirStringList = NULL;
if ((dirStringList = (char **) malloc(need * sizeof(char *)))
== NULL) {
showError(
"Unable to allocate sufficient memory to display this directory.");
changeDirList(emptyList);
return;
}
}
if (current != NULL) {
changeDirLabel(USER_STRING(current->selectorItem));
} else {
changeDirLabel("Empty Directory");
}
i = 0;
if (current != NULL) {
if ((gi = current->contents.first) != NULL) {
while ( gi != NULL) {
dirStringList[i] = USER_STRING_PREFIX(gi);
i++;
gi = nextItem(gi);
}
}
}
dirStringList[i] = (char *) NULL;
changeDirList(dirStringList);
return;
}
/* displayBookmarks
display the current bookmark list. */
void
displayBookmarks()
{
gopherItemP gi;
int i, need;
static int markStringListLen = 0;
static char **markStringList = NULL;
if (!windowStarted) return;
/* The array of string pointers is allocated a reasonably
large amount initially. After this, if more are needed,
the current array is freed, then the new required number
is allocated. */
need = markListLength() + 1;
if (need > markStringListLen) {
need = need > MIN_MARK_STRING_LIST_LEN ?
need : MIN_MARK_STRING_LIST_LEN;
if (markStringList != NULL) free(markStringList);
markStringList = NULL;
if ((markStringList = (char **) malloc(need * sizeof(char *)))
== NULL) {
showError(
"Unable to allocate sufficient memory to display the bookmark list.");
changeMarkList(emptyList);
return;
}
}
i = 0;
if ((gi = firstMark()) != NULL) {
while (gi != NULL) {
markStringList[i] = USER_STRING_PREFIX(gi);
i++;
gi = nextItem(gi);
}
}
markStringList[i] = (char *) NULL;
changeMarkList(markStringList);
return;
}
/* checkPanelButtons
ensure that the panel buttons have proper sensitivity. */
void
checkPanelButtons()
{
checkButtonState(BS_all);
}
/* clearBookmarks
properly clear the bookmark list. */
void
clearBookmarks()
{
unmarkAllProc(NULL, NULL, NULL);
}
/* showFile
display a file on the screen. */
void
showFile(gi, title, fileName, indexString)
gopherItemP gi;
char *title;
char *fileName;
char *indexString;
{
if (! windowStarted) return;
if (! saveDialogExists) {
makeSaveDialog(topLevel);
saveDialogExists = TRUE;
if (saveWPID != nullWPID) XtRemoveWorkProc (saveWPID);
}
if (indexString == NULL) {
displayTempFile(topLevel, fileTextClass, gi, title, fileName);
} else {
displayIndexTempFile(topLevel, fileTextClass, gi, title,
fileName, indexString);
}
return;
}
/* showNameServer
display a CSO name server panel. */
void
showNameServer(title, s)
char *title;
int s;
{
if (! windowStarted) return;
LOG (logFP, "CSO name server at:%s\n", title);
if (! csoPanelExists) {
makeCsoPanel(topLevel);
csoPanelExists = TRUE;
if (csoWPID != nullWPID) XtRemoveWorkProc (csoWPID);
}
if (! displayCsoPanel(title, s)) {
showError(
"Cannot display CSO Name Server\n(Is one already active?)");
}
return;
}
/* showIndex
display a Index search panel. */
void
showIndex(gi)
gopherItemP gi;
{
if (! windowStarted) return;
LOG (logFP, "Index search:%s\n", USER_STRING(gi));
if (! indexPanelExists) {
makeIndexPanel(topLevel);
indexPanelExists = TRUE;
if (indexWPID != nullWPID) XtRemoveWorkProc (indexWPID);
}
displayIndexPanel((XtPointer) gi, USER_STRING(gi));
return;
}
/* showOptionsPanel
display the options panel. */
void
showOptionsPanel()
{
if (! windowStarted) return;
if (! optionsPanelExists) {
makeOptionsPanel(topLevel);
optionsPanelExists = TRUE;
if (optionsWPID != nullWPID) XtRemoveWorkProc (optionsWPID);
}
displayOptionsPanel();
return;
}
/* showSinglePanel
display the single gopher item entry panel. */
void
showSinglePanel()
{
if (! windowStarted) return;
if (! singlePanelExists) {
makeSinglePanel(topLevel);
singlePanelExists = TRUE;
if (singleWPID != nullWPID) XtRemoveWorkProc (singleWPID);
}
displaySinglePanel();
return;
}
/* showHelp
show a help item in a text window */
void
showHelp(key)
char *key;
{
char *string;
char title[HELP_SEC_TITLE_LEN];
string = getHelpText(key, title);
if (string == NULL)
showError ("No help is available.");
else if (title[0] == '\0')
displayTextString(topLevel, helpTextClass, (gopherItemP) NULL,
"Gopher Assistance", string);
else
displayTextString(topLevel, helpTextClass, (gopherItemP) NULL,
title, string);
return;
}
/* showItemInfo
show information about a gopher item in a text window */
void
showItemInfo(gi)
gopherItemP gi;
{
char *string;
string = getItemInfoText(gi, 0);
if (string == NULL)
showError ("No information on this item is available.");
else
displayTextString(topLevel, infoTextClass, (gopherItemP) NULL,
"Information", string);
return;
}
/* setPopupGeometry
preset the geometry specification for topLevelShell's before they
are realized. */
void
setPopupGeometry(w, placement)
Widget w;
popupPosResources *placement;
{
Arg args[5];
Cardinal n;
Position rootX, rootY;
Dimension popupWidth, popupHeight;
Dimension screenWidth, screenHeight;
if (w == NULL) return;
if (XtClass(w) != topLevelShellWidgetClass) return;
if (placement->positionFrom == from_none) return;
/* the value "+0+0" is sufficient to let us
move the window later when it is displayed. */
XtSetArg(args[0], XtNgeometry, "+0+0");
XtSetValues(w, args, (Cardinal) 1);
return;
}
/* findPopupPosition
Auxiliary routine used by positionAPopup. This routine computes the
target position on the root window, but doesn't actually do the move */
void
findPopupPosition(w, fromWidget, placement, rootX, rootY)
Widget w;
Widget fromWidget;
popupPosResources *placement;
Position *rootX, *rootY;
{
/*
w is the popup widget.
fromWidget is the shell widget to position relative to
(for from_main or from_widget)
placement is a struct containing the positioning information.
*/
Arg args[5];
Cardinal n;
Dimension popupWidth, popupHeight;
Dimension screenWidth, screenHeight;
*rootX = 0;
*rootY = 0;
if (w == NULL) return;
if (placement->positionFrom == from_none) return;
screenWidth = WidthOfScreen(XtScreen(w));
screenHeight = HeightOfScreen(XtScreen(w));
if (XtClass(w) == transientShellWidgetClass) {
XtRealizeWidget(w);
}
/* find a reference point */
switch (placement->positionFrom) {
case from_pointer:
{
Window root, child;
int ptrX, ptrY, winX, winY;
unsigned int keysButtons;
XQueryPointer(XtDisplay(w), XtWindow(XtParent(w)),
&root, &child, &ptrX, &ptrY, &winX, &winY,
&keysButtons);
*rootX = (Position) ptrX;
*rootY = (Position) ptrY;
}
break;
case from_main:
case from_widget:
{
Dimension panelWidth, panelHeight;
Position relX, relY;
n = 0;
XtSetArg(args[n], XtNwidth, &panelWidth); n++;
XtSetArg(args[n], XtNheight, &panelHeight); n++;
XtGetValues(fromWidget, args, n);
if (placement->xPercent) {
relX = ((int) panelWidth * placement->xPosition)
/ 100;
} else {
relX = placement->xPosition;
}
if (placement->yPercent) {
relY = ((int) panelHeight * placement->yPosition)
/ 100;
} else {
relY = placement->yPosition;
}
XtTranslateCoords(fromWidget, relX, relY, rootX, rootY);
}
break;
case from_screen:
{
if (placement->xPercent) {
*rootX = ((int) screenWidth * placement->xPosition)
/ 100;
} else {
*rootX = placement->xPosition;
}
if (placement->yPercent) {
*rootY = ((int) screenHeight * placement->yPosition)
/ 100;
} else {
*rootY = placement->yPosition;
}
}
break;
}
/* apply justification left/right, top/bottom */
n = 0;
XtSetArg(args[n], XtNwidth, &popupWidth); n++;
XtSetArg(args[n], XtNheight, &popupHeight); n++;
XtGetValues(w, args, n);
if (placement->horizontalJustification == justify_center)
*rootX -= popupWidth / 2;
else if (placement->horizontalJustification == justify_bottom_right)
*rootX -= popupWidth;
if (placement->verticalJustification == justify_center)
*rootY -= popupHeight / 2;
else if (placement->verticalJustification == justify_bottom_right)
*rootY -= popupHeight;
/* force the popup to be on screen */
if (*rootX < 0) *rootX = 0;
else if ((int) *rootX + (int) popupWidth > (int) screenWidth)
*rootX = screenWidth - popupWidth;
if (*rootY < 0) *rootY = 0;
else if ((int) *rootY + (int) popupHeight > (int) screenHeight)
*rootY = screenHeight - popupHeight;
}
/* positionAPopup
set the position of a popup window. */
void
positionAPopup(w, fromWidget, placement)
Widget w;
Widget fromWidget;
popupPosResources *placement;
{
/*
w is the popup widget.
fromWidget is the shell widget to position relative to
(for from_main or from_widget)
placement is a struct containing the positioning information.
*/
Arg args[5];
Cardinal n;
Position rootX, rootY;
if (w == NULL) return;
if (placement->positionFrom == from_none) return;
findPopupPosition(w, fromWidget, placement, &rootX, &rootY);
if (XtClass(w) == transientShellWidgetClass) {
/*
XtMoveWidget(w, (Position) rootX, (Position) rootY);
*/
n = 0;
XtSetArg(args[n], XtNx, rootX); n++;
XtSetArg(args[n], XtNy, rootY); n++;
XtSetValues(w, args, n);
} else if (XtIsRealized(w)) {
XMoveWindow(XtDisplay(w), XtWindow(w),
(int) rootX, (int) rootY);
} else {
/* we likely won't get here because most popups
are realized earlier in order to install the
ICCCM event handling easily. */
static char geom[16];
sprintf(geom, "+%d+%d", (int) rootX, (int) rootY);
XtSetArg(args[0], XtNgeometry, geom);
XtSetValues(w, args, (Cardinal) 1);
}
return;
}
/* setTextWidgetSize
Use the selected font size and other attributes to set the
size of a text widget. This routine should be called just
after a text widget is created. */
void
setTextWidgetSize(textWidget, width, height)
Widget textWidget;
int width, height;
{
XawTextWrapMode wrap;
XFontStruct *textFontStruct;
int direction, ascent, descent;
XCharStruct overall;
Position topMargin, bottomMargin;
Position leftMargin, rightMargin;
Dimension w, h;
Arg args[10];
Cardinal n;
if (textWidget == NULL) return;
n=0;
if (height > 1) {
XtSetArg(args[n], XtNwrap, &wrap); n++;
}
XtSetArg(args[n], XtNfont, &textFontStruct); n++;
XtSetArg(args[n], XtNtopMargin, &topMargin); n++;
XtSetArg(args[n], XtNbottomMargin, &bottomMargin); n++;
XtSetArg(args[n], XtNleftMargin, &leftMargin); n++;
XtSetArg(args[n], XtNrightMargin, &rightMargin); n++;
XtGetValues(textWidget, args, n);
if (height > 1) {
if (wrap == XawtextWrapNever) {
n=0;
XtSetArg(args[n], XtNscrollHorizontal,
XawtextScrollWhenNeeded); n++;
XtSetValues(textWidget, args, n);
}
}
/* use some randomly-sized characters to get width in case
it is a proportionately-spaced font */
XTextExtents(textFontStruct, "mljf", 4,
&direction, &ascent, &descent, &overall);
w = (Dimension) ( leftMargin + rightMargin +
(int) (overall.width * ( (float) width / 4.0) ) );
h = (Dimension) ( (topMargin + bottomMargin) +
( (ascent + descent) * height) );
/* The following is a hack.
The scrollbar steals away space from the text content
of the window if and when it is displayed. If
"scrollWhenNeeded" is set, then the scrollbar does not
exist yet and may not ever exist. So we have no way
to find out its width.
We're not as likely to have a horizontal bar as a vertical
one, so ignore the horizontal one. It's less crucial.
However, we'd like to always provide a text display which
is at least 80 characters wide by default.
So, We'll just add 14 pixels for the scrollbar thickness.
Which is the default provided in the Xaw Scrollbar.c
source. I hate doing this, but there seems to be no
other way. We'll similarly add 2 pixels for border
width, then quietly slink off into the night.
*/
w = w + 16;
n=0;
XtSetArg(args[n], XtNwidth, w); n++;
XtSetArg(args[n], XtNheight, h); n++;
XtSetValues(textWidget, args, n);
}
/* getTextSize
To find out the size in pixels required to hold a certain number of
rows and columns of text, given the font and other attributes
of a widget. This routine should only be called for widgets
which contain text, such as label and list. */
void
getTextSize(someWidget, width, height, w, h)
Widget someWidget;
int width, height;
Dimension *w, *h;
{
XawTextWrapMode wrap;
XFontStruct *textFontStruct;
int direction, ascent, descent;
XCharStruct overall;
Position topMargin, bottomMargin;
Arg args[10];
Cardinal n;
if (someWidget == NULL) return;
n=0;
XtSetArg(args[n], XtNfont, &textFontStruct); n++;
XtGetValues(someWidget, args, n);
/* use some randomly-sized characters to get width in case
it is a proportionately-spaced font */
XTextExtents(textFontStruct, "mljf", 4,
&direction, &ascent, &descent, &overall);
*w = (Dimension) ((int) (overall.width * ( (float) width / 4.0) ) );
*h = (Dimension) (ascent + descent) * height;
}
static BOOLEAN ding = FALSE;
#define MAX_WAIT_TIME 3000 /* milliseconds */
/* maxWaitTimeProc
we don't want to be dispatching events for more than this time */
static void
maxWaitTimeProc(clientData, id)
XtPointer clientData;
XtIntervalId *id;
{
ding = TRUE;
}
/* WaitForAllPendingEventsAndExpose
Clears out the event queue and optionally waits until it sees
an expose event for a specific window. In the latter case,
it will also offer a timeout to prevent indefinite hangs. */
void
WaitForAllPendingEventsAndExpose(dpy, needToSee)
Display *dpy;
Window needToSee;
{
static XEvent event;
BOOLEAN gotExposed=FALSE;
XtIntervalId waitTimerId = (XtIntervalId) 0;
XSync(dpy, False);
if (needToSee == (Window) NULL) {
while( XtAppPending (appcon) ) {
XtAppNextEvent(appcon, &event);
XtDispatchEvent (&event);
}
} else {
/* empty the event queue, and keep doing so until we
see a specific expose event or until were tired
of waiting. */
waitTimerId = XtAppAddTimeOut(appcon, MAX_WAIT_TIME,
maxWaitTimeProc, NULL);
ding = FALSE;
while( XtAppPending (appcon) || (!gotExposed && !ding)) {
XtAppNextEvent(appcon, &event);
if (event.type == Expose &&
event.xexpose.window == needToSee) {
gotExposed = TRUE;
}
XtDispatchEvent (&event);
}
if (! ding) {
XtRemoveTimeOut(waitTimerId);
}
}
}